﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chapter18.Controls
{
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Data;

    [TemplatePart(Name = "PART_RedSlider", Type = typeof(RangeBase))]
    [TemplatePart(Name = "PART_BlueSlider", Type = typeof(RangeBase))]
    [TemplatePart(Name = "PART_GreenSlider", Type = typeof(RangeBase))]
    [TemplatePart(Name = "PART_PreviewBrush", Type = typeof(SolidColorBrush))]
    public class ColorPicker : Control
    {
        public static readonly DependencyProperty ColorProperty;
        public static readonly DependencyProperty RedProperty;
        public static readonly DependencyProperty GreenProperty;
        public static readonly DependencyProperty BlueProperty;
        public static readonly RoutedEvent ColorChangedEvent;

        private Color? previousColor;

        public Color Color
        {
            get { return (Color)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }

        public byte Red
        {
            get { return (byte)GetValue(RedProperty); }
            set { SetValue(RedProperty, value); }
        }

        public byte Green
        {
            get { return (byte)GetValue(GreenProperty); }
            set { SetValue(GreenProperty, value); }
        }

        public byte Blue
        {
            get { return (byte)GetValue(BlueProperty); }
            set { SetValue(BlueProperty, value); }
        }

        public event RoutedPropertyChangedEventHandler<Color> ColorChanged
        {
            add { AddHandler(ColorChangedEvent, value); }
            remove { RemoveHandler(ColorChangedEvent, value); }
        }

        static ColorPicker()
        {
            ColorProperty = DependencyProperty.Register(
                "Color", typeof(Color), typeof(ColorPicker), new PropertyMetadata(Colors.Black, new PropertyChangedCallback(OnColorChanged)));

            RedProperty = DependencyProperty.Register(
                "Red", typeof(byte), typeof(ColorPicker), new PropertyMetadata(OnColorRGBChanged));

            GreenProperty = DependencyProperty.Register(
                "Green", typeof(byte), typeof(ColorPicker), new PropertyMetadata(OnColorRGBChanged));

            BlueProperty = DependencyProperty.Register(
                "Blue", typeof(byte), typeof(ColorPicker), new PropertyMetadata(OnColorRGBChanged));

            ColorChangedEvent = EventManager.RegisterRoutedEvent(
                "ColorChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<Color>), typeof(ColorPicker));

            CommandManager.RegisterClassCommandBinding(typeof(ColorPicker), new CommandBinding(ApplicationCommands.Undo, UndoCommand_Executed, UndoCommand_CanExecute));

            DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));
        }


        public ColorPicker()
        {

        }

        private static void OnColorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var newColor = (Color)e.NewValue;
            var oldColor = (Color)e.OldValue;
            var colorPicker = (ColorPicker)sender;
            colorPicker.Red = newColor.R;
            colorPicker.Green = newColor.G;
            colorPicker.Blue = newColor.B;
            colorPicker.previousColor = oldColor;
            colorPicker.OnColorChanged(new RoutedPropertyChangedEventArgs<Color>(oldColor, newColor, ColorPicker.ColorChangedEvent));
        }

        private static void OnColorRGBChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var colorPicker = (ColorPicker)sender;
            var color = colorPicker.Color;
            if (e.Property == RedProperty)
            {
                color.R = (byte)e.NewValue;
            }
            else if (e.Property == GreenProperty)
            {
                color.G = (byte)e.NewValue;
            }
            else if (e.Property == BlueProperty)
            {
                color.B = (byte)e.NewValue;
            }
            colorPicker.Color = color;
        }

        private static void UndoCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            var colorPicker = (ColorPicker)sender;
            var currentColor = colorPicker.Color;
            colorPicker.Color = (Color)colorPicker.previousColor;
        }

        private static void UndoCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            var colorPicker = (ColorPicker)sender;
            e.CanExecute = colorPicker.previousColor.HasValue;
        }

        protected virtual void OnColorChanged(RoutedPropertyChangedEventArgs<Color> e)
        {
            RaiseEvent(e);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            var slider = GetTemplateChild("PART_RedSlider") as RangeBase;
            if (slider != null)
            {
                var binding = new Binding("Red");
                binding.Source = this;
                binding.Mode = BindingMode.TwoWay;
                slider.SetBinding(RangeBase.ValueProperty, binding);
            }
            slider = GetTemplateChild("PART_GreenSlider") as RangeBase;
            if (slider != null)
            {
                var binding = new Binding("Green");
                binding.Source = this;
                binding.Mode = BindingMode.TwoWay;
                slider.SetBinding(RangeBase.ValueProperty, binding);
            }
            slider = GetTemplateChild("PART_BlueSlider") as RangeBase;
            if (slider != null)
            {
                var binding = new Binding("Blue");
                binding.Source = this;
                binding.Mode = BindingMode.TwoWay;
                slider.SetBinding(RangeBase.ValueProperty, binding);
            }
            var brush = GetTemplateChild("PART_PreviewBrush") as SolidColorBrush;
            if (brush != null)
            {
                var binding = new Binding("Color");
                binding.Source = brush;
                binding.Mode = BindingMode.OneWayToSource;
                SetBinding(ColorPicker.ColorProperty, binding);
            }
        }
    }
}
